<template>
  <div class="tui-select-container" :class="[
    `tui-select-container--${size}`,
    { 'tui-select-container--multiple': multiple },
    { 'tui-select-container--disabled': disabled },
    { 'tui-select-container--focus': isFocused }
  ]">
    <!-- 基础选择框 -->
    <select :id="id" :name="name" :disabled="disabled" :required="required" :multiple="multiple" class="tui-select" @change="handleChange" @focus="handleFocus" @blur="handleBlur">
      <option v-if="placeholder" :value="''" disabled>{{ placeholder }}</option>

      <!-- 渲染通过 options 属性传递的选项 -->
      <template v-if="shouldRenderFromOptions">
        <option v-for="option in mergedOptions" :key="option[valueKey as keyof TuiOptionProps] as string || option.value as string" :value="option.value" :disabled="option.disabled" :selected="isSelected(option.value)">
          {{ option.label }}
        </option>
      </template>

      <!-- 渲染通过 tui-option 子组件传递的选项 -->
      <template v-else>
        <slot></slot>
      </template>
    </select>

    <!-- 清空按钮 -->
    <button v-if="clearable && modelValue && !disabled" class="tui-select-clear-btn" @click.stop="handleClear" title="清空">
      ×
    </button>

    <!-- 加载状态 -->
    <div v-if="loading" class="tui-select-loading">
      <span class="tui-select-loading-text">{{ loadingText }}</span>
    </div>

    <!-- 错误信息 -->
    <p v-if="errorMessage" class="tui-select-error">{{ errorMessage }}</p>
  </div>
</template>

<script lang="ts" setup>

// 从Option组件导入类型
import { type TuiOptionProps } from './types';

// 定义组件props接口
export interface SelectProps {
  /**
   * 选择框的id
   */
  id?: string;

  /**
   * 选择框的name属性
   */
  name?: string;

  /**
   * 绑定的值
   */
  modelValue?: string | number | object | (string | number | object)[];

  /**
   * 占位符文本
   */
  placeholder?: string;

  /**
   * 是否禁用
   */
  disabled?: boolean;

  /**
   * 是否必填
   */
  required?: boolean;

  /**
   * 选项列表
   */
  options?: TuiOptionProps[];

  /**
   * 错误信息
   */
  errorMessage?: string;

  /**
   * 是否多选
   */
  multiple?: boolean;

  /**
   * 是否可以清空选项
   */
  clearable?: boolean;

  /**
   * 输入框尺寸
   */
  size?: 'large' | 'default' | 'small';

  /**
   * 多选时是否将选中值按文字的形式展示
   */
  collapseTags?: boolean;

  /**
   * 当鼠标悬停于折叠标签的文字上时，显示所有选中的标签
   */
  collapseTagsTooltip?: boolean;

  /**
   * 多选时最多显示多少个标签
   */
  maxCollapseTags?: number;

  /**
   * 是否可搜索
   */
  filterable?: boolean;

  /**
   * 自定义搜索方法
   */
  filterMethod?: (value: string, option: TuiOptionProps) => boolean;

  /**
   * 是否为远程搜索
   */
  remote?: boolean;

  /**
   * 远程搜索方法
   */
  remoteMethod?: (query: string) => void;

  /**
   * 是否正在从远程获取数据
   */
  loading?: boolean;

  /**
   * 远程加载时的文字提示
   */
  loadingText?: string;

  /**
   * 无数据时的文字提示
   */
  noDataText?: string;

  /**
   * 搜索条件无匹配时的文字提示
   */
  noMatchText?: string;

  /**
   * 作为value唯一标识的键名，绑定值为对象类型时必填
   */
  valueKey?: string;

  /**
   * 允许创建新条目
   */
  allowCreate?: boolean;

  /**
   * 远程搜索显示后缀
   */
  remoteShowSuffix?: boolean;

  /**
   * 空值配置
   */
  emptyValues?: (string | null | undefined)[];

  /**
   * 清空时返回的值
   */
  valueOnClear?: string | null | undefined;
}

// 使用withDefaults定义props和默认值
const props = withDefaults(defineProps<SelectProps>(), {
  id: '',
  name: '',
  modelValue: '',
  placeholder: '',
  disabled: false,
  required: false,
  options: () => [],
  errorMessage: '',
  multiple: false,
  clearable: false,
  size: 'default',
  collapseTags: false,
  collapseTagsTooltip: false,
  maxCollapseTags: 0,
  filterable: false,
  filterMethod: undefined,
  remote: false,
  remoteMethod: undefined,
  loading: false,
  loadingText: '加载中...',
  noDataText: '无数据',
  noMatchText: '无匹配数据',
  valueKey: 'value',
  allowCreate: false,
  remoteShowSuffix: false,
  emptyValues: () => [null, undefined],
  valueOnClear: '',
});

import { ref, computed, useSlots, onMounted } from 'vue';

// 验证options格式
if (props.options.length > 0) {
  const isValid = props.options.every(option => {
    const hasRequiredProps = 'value' in option;
    return hasRequiredProps;
  });

  if (!isValid) {
    console.warn('tui-select: options must be an array of objects with value property');
  }
}

// 状态变量
const isFocused = ref(false);
const slots = useSlots();

// 判断是否使用 options 属性渲染（优先级：子组件 > options属性）
const shouldRenderFromOptions = computed(() => {
  // 检查默认插槽中是否有 tui-option 子组件
  const hasOptionChildren = slots.default?.().some(child => {
    // 添加类型安全检查，确保 child.type 是一个对象且具有 name 或 __name 属性
    return (
      child.type &&
      typeof child.type === 'object' &&
      ['TuiOption', 'Option'].includes((child.type as any).name || (child.type as any).__name || '')
    );
  }) || false;

  // 优先级逻辑：如果有tui-option子组件，则优先使用子组件方式渲染
  if (hasOptionChildren) {
    return false;
  }

  // 否则，如果提供了有效的options属性，则使用options属性渲染
  return props.options && Array.isArray(props.options) && props.options.length > 0;
});

// 获取合并后的选项（这里主要是为了保持一致性）
const mergedOptions = computed(() => {
  return props.options || [];
});

// 判断选项是否被选中
const isSelected = (value: string | number | object) => {
  if (props.multiple && Array.isArray(props.modelValue)) {
    return props.modelValue.includes(value);
  } else {
    return props.modelValue === value;
  }
};

// 定义emits
const emit = defineEmits<{
  (e: 'update:modelValue', value: string | number | object | (string | number | object)[]): void;
  (e: 'change', value: string | number | object | (string | number | object)[], event: Event): void;
  (e: 'focus', event: FocusEvent): void;
  (e: 'blur', event: FocusEvent): void;
  (e: 'clear'): void;
  (e: 'visible-change', visible: boolean): void;
  (e: 'remove-tag', value: string | number | object): void;
}>();

// 处理变化事件
const handleChange = (event: Event) => {
  const target = event.target as HTMLSelectElement;
  let value: string | number | object | (string | number | object)[];

  if (props.multiple) {
    // 多选情况
    value = Array.from(target.selectedOptions).map(option => {
      const optionValue = option.value;
      // 尝试将值转换回原始类型
      const originalOption = props.options.find(opt =>
        (props.valueKey ? opt[props.valueKey as keyof typeof opt] : opt.value) === optionValue
      );
      return originalOption ? (props.valueKey ? originalOption[props.valueKey as keyof typeof originalOption] : originalOption.value) : optionValue;
    });
  } else {
    // 单选情况
    value = target.value;
    // 尝试将值转换回原始类型
    const originalOption = props.options.find(opt =>
      (props.valueKey ? opt[props.valueKey as keyof typeof opt] : opt.value) === value
    );
    if (originalOption) {
      value = props.valueKey ? originalOption[props.valueKey as keyof typeof originalOption] : originalOption.value;
    }
  }

  emit('update:modelValue', value);
  emit('change', value, event);
};

// 处理聚焦事件
const handleFocus = (event: FocusEvent) => {
  isFocused.value = true;
  emit('focus', event);
  emit('visible-change', true);
};

// 处理失焦事件
const handleBlur = (event: FocusEvent) => {
  isFocused.value = false;
  emit('blur', event);
  emit('visible-change', false);
};

// 处理清空事件
const handleClear = () => {
  const clearValue = props.valueOnClear !== undefined ? props.valueOnClear : '';
  emit('update:modelValue', clearValue);
  emit('clear');
  emit('change', clearValue as string | number | object | (string | number | object)[], new Event('change'));
};
</script>

<style lang="scss" scoped>
.tui-select-container {
  display: flex;
  flex-direction: column;
  width: 100%;
  position: relative;

  &.tui-select-container--large {
    .tui-select {
      height: 40px;
      font-size: var(--tui-font-size-large, 18px);
      padding: 10px 12px;
    }
  }

  &.tui-select-container--small {
    .tui-select {
      height: 32px;
      font-size: var(--tui-font-size-small, 12px);
      padding: 6px 12px;
    }
  }

  &.tui-select-container--multiple {
    .tui-select {
      min-height: 36px;
      height: auto;
      padding: 4px 12px;
    }
  }

  &.tui-select-container--focus {
    .tui-select {
      border-color: var(--tui-color-primary);
      box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
    }
  }

  .tui-select {
    width: 100%;
    padding: 8px 12px;
    border: 1px solid var(--tui-color-border);
    border-radius: 4px;
    font-size: var(--tui-font-size-base, 14px);
    box-sizing: border-box;
    transition: border-color 0.3s, box-shadow 0.3s;
    background-color: var(--tui-color-white);
    height: 36px;
    line-height: 1.5;

    &:focus {
      outline: none;
      border-color: var(--tui-color-primary);
      box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
    }

    &:disabled {
      background-color: var(--tui-color-bg-light);
      cursor: not-allowed;
      opacity: 0.6;
    }
  }

  .tui-select-clear-btn {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    width: 20px;
    height: 20px;
    padding: 0;
    border: none;
    background-color: transparent;
    color: var(--tui-color-text-secondary);
    font-size: 20px;
    cursor: pointer;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    transition: background-color 0.3s, color 0.3s;

    &:hover {
      background-color: var(--tui-color-bg-light);
      color: var(--tui-color-text-primary);
    }
  }

  .tui-select-loading {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    color: var(--tui-color-text-secondary);

    .tui-select-loading-text {
      font-size: 12px;
    }
  }

  &-error {
    color: var(--tui-color-danger);
    font-size: 12px;
    margin-top: 4px;
    margin-bottom: 0;
  }
}
</style>